package com.vr.xuecheng.content.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vr.xuecheng.base.exception.XueChengPlusException;
import com.vr.xuecheng.base.response.Result;
import com.vr.xuecheng.content.mapper.TeachPlanMapper;
import com.vr.xuecheng.content.model.dto.AddOrUpdateTeachPlanParamsDTO;
import com.vr.xuecheng.content.model.dto.TeachPlanMediaDTO;
import com.vr.xuecheng.content.model.entity.TeachPlan;
import com.vr.xuecheng.content.model.entity.TeachPlanMedia;
import com.vr.xuecheng.content.model.vo.TeachPlanWithTreeVO;
import com.vr.xuecheng.content.service.ITeachPlanMediaService;
import com.vr.xuecheng.content.service.ITeachPlanService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程计划 服务实现类
 * </p>
 *
 * @author hsh
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TeachPlanServiceImpl extends ServiceImpl<TeachPlanMapper, TeachPlan> implements ITeachPlanService {

    private final TeachPlanMapper teachPlanMapper;
    private final ITeachPlanMediaService teachPlanMediaService;

    @Override
    public List<Tree<Long>> getTreeNodesById(Long courseId) {
        if (courseId == null) {
            return Collections.emptyList();
        }
        // 1、获取课程id关联的课程计划
        List<TeachPlan> teachPlanList = teachPlanMapper.selectList(new QueryWrapper<TeachPlan>().lambda()
                .eq(TeachPlan::getCourseId, courseId)
                .orderByAsc(TeachPlan::getOrderby)
        );
        if (teachPlanList.isEmpty()) {
            return Collections.emptyList();
        }
        // 转成vo
        // 2、获取2级及2级下的课程计划关联的媒体的映射map
        List<Long> teachPlanIds = teachPlanList.stream().filter(teachPlan -> teachPlan.getGrade() >= 2).map(TeachPlan::getId).toList();
        Map<Long, TeachPlanMedia> mapOfIdToTeachPlanMedia = Collections.emptyMap();
        // 有视频关联时才查询
        if (!teachPlanIds.isEmpty()) {
            mapOfIdToTeachPlanMedia = teachPlanMediaService.lambdaQuery()
                    .in(TeachPlanMedia::getTeachplanId, teachPlanIds)
                    .list().stream()
                    .collect(Collectors.toMap(TeachPlanMedia::getTeachplanId, teachPlanMedia -> teachPlanMedia));
        }
        // 3、将课程计划列表转成树形结构
        return this.buildTree(teachPlanList, mapOfIdToTeachPlanMedia);
    }

    /**
     * @param req 新增或更新参数
     * @return {@code Result<String> } 结果
     */
    @Override
    @Transactional
    public Result<String> addOrUpdateTeachPlan(AddOrUpdateTeachPlanParamsDTO req) {
        int row = 0;
        if (req.getId() != null) {
            // 更新操作
            TeachPlan teachPlan = teachPlanMapper.selectById(req.getId());
            if (teachPlan == null) {
                XueChengPlusException.cast("课程计划不存在");
            }
            // 数据合并
            BeanUtil.copyProperties(req, teachPlan);
            row = teachPlanMapper.updateById(teachPlan);
            // 教学计划排序比重默认是从orderBy从小到大排序
        } else {
            // 新增操作
            TeachPlan newTeachPlan = BeanUtil.toBean(req, TeachPlan.class);
            // 设置比重，越大则越靠后，新增的永远是最后，orderBy去当前所在父节点里的orderBy最大值加1
            // 获取当前课程所在当前父节点下所以子节点
            List<TeachPlan> teachPlanList = teachPlanMapper.selectList(new QueryWrapper<TeachPlan>().lambda()
                    .eq(TeachPlan::getParentid, req.getParentid())
                    .eq(TeachPlan::getCourseId, req.getCourseId())
            );
            Optional<TeachPlan> optional = teachPlanList.stream().max((o1, o2) -> Integer.compare(o1.getOrderby(), o2.getOrderby()));
            optional.ifPresentOrElse(
                    // 新增的教学计划的orderB是最大的orderBy值加1
                    teachPlan -> {
                        newTeachPlan.setOrderby(teachPlan.getOrderby() + 1);
                    },
                    // 如果父节点下没有子节点，则新增的教学计划的orderBy为1
                    () -> newTeachPlan.setOrderby(1));

            row = teachPlanMapper.insert(newTeachPlan);
        }
        return Result.toResult(row);
    }

    @Override
    public Result<String> moveUp(Long id) {
        if (id == null) {
            XueChengPlusException.cast("id为空");
        }
        TeachPlan teachPlan = teachPlanMapper.selectById(id);
        if (teachPlan == null) {
            XueChengPlusException.cast("id无效");
        }
        // 获取当前课程所在当前父节点下所以子节点
        List<TeachPlan> teachPlanList = teachPlanMapper.selectList(new QueryWrapper<TeachPlan>().lambda()
                .eq(TeachPlan::getParentid, teachPlan.getParentid())
                .eq(TeachPlan::getCourseId, teachPlan.getCourseId())
                .orderByAsc(TeachPlan::getOrderby)
        );
        int currentIndex = teachPlanList.indexOf(teachPlan);
        if (currentIndex == 0) {
            XueChengPlusException.cast("已经是最上了");

        }
        // 当前的与上面交换
        Result.toResult(teachPlanMapper.update(null,
                new UpdateWrapper<TeachPlan>().lambda()
                        .set(TeachPlan::getOrderby, currentIndex)
                        .eq(TeachPlan::getId, id)
        ));
        Result.toResult(teachPlanMapper.update(null,
                new UpdateWrapper<TeachPlan>().lambda()
                        .set(TeachPlan::getOrderby, currentIndex + 1)
                        .eq(TeachPlan::getId, teachPlanList.get(currentIndex - 1).getId())
        ));
        return Result.toResult(1);
    }

    @Override
    @Transactional
    public Result<String> moveDown(Long id) {
        if (id == null) {
            XueChengPlusException.cast("id为空");
        }
        TeachPlan teachPlan = teachPlanMapper.selectById(id);
        if (teachPlan == null) {
            XueChengPlusException.cast("id无效");
        }

        // 获取当前课程所在当前父节点下所以子节点
        List<TeachPlan> teachPlanList = teachPlanMapper.selectList(new QueryWrapper<TeachPlan>().lambda()
                .eq(TeachPlan::getParentid, teachPlan.getParentid())
                .eq(TeachPlan::getCourseId, teachPlan.getCourseId())
                .orderByAsc(TeachPlan::getOrderby)
        );
        // 当前节点索引
        int currentIndex = teachPlanList.indexOf(teachPlan);
        if (currentIndex == teachPlanList.size() - 1) {
            XueChengPlusException.cast("已经是最下了");
        }
        // 与下面的节点交换顺序
        // 上面节点往下移动
        teachPlanMapper.update(null,
                new UpdateWrapper<TeachPlan>().lambda()
                        .set(TeachPlan::getOrderby, currentIndex + 2)
                        .eq(TeachPlan::getId, id));
        // 下面节点往上移动
        teachPlanMapper.update(null,
                new UpdateWrapper<TeachPlan>().lambda()
                        .set(TeachPlan::getOrderby, currentIndex + 1)
                        .eq(TeachPlan::getId, teachPlanList.get(currentIndex + 1).getId()));
        return Result.toResult(1);
    }

    @Transactional
    @Override
    public boolean relevanceMedia(TeachPlanMediaDTO req) {
        // 删除之前关联的
         teachPlanMediaService.remove(new QueryWrapper<TeachPlanMedia>().lambda().eq(TeachPlanMedia::getTeachplanId, req.getTeachplanId()));
        TeachPlan teachPlan = teachPlanMapper.selectById(req.getTeachplanId());
        return teachPlanMediaService.save(TeachPlanMedia.builder()
                .teachplanId(req.getTeachplanId())
                .mediaId(req.getMediaId())
                .courseId(teachPlan.getCourseId())
                .mediaFilename(req.getFileName())
                .build());
    }

    private List<Tree<Long>> buildTree(List<TeachPlan> teachPlanList, Map<Long, TeachPlanMedia> mapOfIdToTeachPlanMedia) {
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 配置树形结构的key
        treeNodeConfig.setWeightKey("orderby");
        treeNodeConfig.setNameKey("pname");
        treeNodeConfig.setChildrenKey("teachPlanTreeNodes");


        // 其他字段
        return TreeUtil.build(teachPlanList, 0L, treeNodeConfig, (teachPlan, treeNode) -> {
            treeNode.setId(teachPlan.getId()).
                    setName(teachPlan.getPname())
                    .setParentId(teachPlan.getParentid())
                    .setWeight(teachPlan.getOrderby())
                    .setWeight(teachPlan.getOrderby());
            // 其他字段
            if (teachPlan.getGrade() >= 2) {
                treeNode.putExtra("teachplanMedia", mapOfIdToTeachPlanMedia.getOrDefault(teachPlan.getId(), null));
            }
            TeachPlanWithTreeVO teachPlanWithTreeVO = BeanUtil.toBean(teachPlan, TeachPlanWithTreeVO.class);
            teachPlanWithTreeVO.setTeachplanMedia((TeachPlanMedia) treeNode.get("teachplanMedia"));
            // 拿到每个键值对，添加到treeNode中，让树形节点中的字段与teachPlanWithTreeVO中的字段对应
            BeanUtil.beanToMap(teachPlanWithTreeVO).forEach(treeNode::putExtra);
        });
    }
}
